home *** CD-ROM | disk | FTP | other *** search
- ;; $Id: com32.inc,v 1.9 2005/01/06 22:34:06 hpa Exp $
- ;; -----------------------------------------------------------------------
- ;;
- ;; Copyright 1994-2003 H. Peter Anvin - All Rights Reserved
- ;;
- ;; This program is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- ;; Boston MA 02111-1307, USA; either version 2 of the License, or
- ;; (at your option) any later version; incorporated herein by reference.
- ;;
- ;; -----------------------------------------------------------------------
-
- ;;
- ;; com32.inc
- ;;
- ;; Common code for running a COM32 image
- ;;
-
- ;
- ; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS
- ; .com file. A COM32 image is loaded at address 0x101000, with %esp
- ; set to the high end of usable memory.
- ;
- ; A COM32 image should begin with the magic bytes:
- ; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and
- ; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the
- ; program with an error if run in 16-bit mode.
- ;
- pm_idt: equ 0x100000
- pm_entry: equ 0x101000
-
- bits 16
- section .data
- align 2, db 0
- com32_pmidt:
- dw 8*256 ; Limit
- dd pm_idt ; Address
-
- com32_rmidt:
- dw 0ffffh ; Limit
- dd 0 ; Address
-
- section .text
- is_com32_image:
- push si ; Save file handle
- push dx ; File length held in DX:AX
- push ax
-
- call make_plain_cmdline
- ; Copy the command line into the low cmdline buffer
- mov ax,real_mode_seg
- mov fs,ax
- mov si,cmd_line_here
- mov di,command_line
- mov cx,[CmdLinePtr]
- inc cx ; Include final null
- sub cx,si
- fs rep movsb
-
- call highmemsize ; We need the high memory size...
- call comboot_setup_api ; Set up the COMBOOT-style API
-
- mov edi,pm_entry ; Load address
- pop eax ; File length
- pop si ; File handle
- xor dx,dx ; No padding
- call load_high
- call crlf
-
- com32_start:
- mov ebx,com32_call_start ; Where to go in PM
-
- com32_enter_pm:
- cli
- mov ax,cs
- mov ds,ax
- mov [SavedSSSP],sp
- mov [SavedSSSP+2],ss
- cld
- call a20_test
- jnz .a20ok
- call enable_a20
-
- .a20ok:
- lgdt [bcopy_gdt] ; We can use the same GDT just fine
- lidt [com32_pmidt] ; Set up the IDT
- mov eax,cr0
- or al,1
- mov cr0,eax ; Enter protected mode
- jmp 20h:.in_pm
-
- bits 32
- .in_pm:
- xor eax,eax ; Available for future use...
- mov fs,eax
- mov gs,eax
-
- mov al,28h ; Set up data segments
- mov es,eax
- mov ds,eax
- mov ss,eax
-
- mov esp,[PMESP] ; Load protmode %esp if available
- jmp ebx ; Go to where we need to go
-
- ;
- ; This is invoked right before the actually starting the COM32
- ; progam, in 32-bit mode...
- ;
- com32_call_start:
- ;
- ; Point the stack to the end of high memory
- ;
- mov esp,[word HighMemSize]
-
- ;
- ; Set up the protmode IDT and the interrupt jump buffers
- ; We set these up in the system area at 0x100000,
- ; but we could also put them beyond the stack.
- ;
- mov edi,pm_idt
-
- ; Form an interrupt gate descriptor
- mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
- mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
- xor ecx,ecx
- inc ch ; ecx <- 256
-
- push ecx
- .make_idt:
- stosd
- add eax,8
- xchg eax,ebx
- stosd
- xchg eax,ebx
- loop .make_idt
-
- pop ecx
-
- ; Each entry in the interrupt jump buffer contains
- ; the following instructions:
- ;
- ; 00000000 60 pushad
- ; 00000001 B0xx mov al,<interrupt#>
- ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt
-
- mov eax,0e900b060h
- mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
-
- .make_ijb:
- stosd
- sub [edi-2],cl ; Interrupt #
- xchg eax,ebx
- stosd
- sub eax,8
- xchg eax,ebx
- loop .make_ijb
-
- ; Now everything is set up for interrupts...
-
- push dword com32_farcall ; Farcall entry point
- push dword (1 << 16) ; 64K bounce buffer
- push dword (comboot_seg << 4) ; Bounce buffer address
- push dword com32_intcall ; Intcall entry point
- push dword command_line ; Command line pointer
- push dword 5 ; Argument count
- sti ; Interrupts OK now
- call pm_entry ; Run the program...
- ; ... on return, fall through to com32_exit ...
-
- com32_exit:
- mov bx,com32_done ; Return to command loop
-
- com32_enter_rm:
- cli
- cld
- mov [PMESP],esp ; Save exit %esp
- xor esp,esp ; Make sure the high bits are zero
- jmp 08h:.in_pm16 ; Return to 16-bit mode first
-
- bits 16
- .in_pm16:
- mov ax,18h ; Real-mode-like segment
- mov es,ax
- mov ds,ax
- mov ss,ax
- mov fs,ax
- mov gs,ax
-
- lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT)
- mov eax,cr0
- and al,~1
- mov cr0,eax
- jmp 0:.in_rm
-
- .in_rm: ; Back in real mode
- mov ax,cs ; Set up sane segments
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- lss sp,[SavedSSSP] ; Restore stack
- jmp bx ; Go to whereever we need to go...
-
- com32_done:
- call disable_a20
- sti
- jmp enter_command
-
- ;
- ; 16-bit support code
- ;
- bits 16
-
- ;
- ; 16-bit interrupt-handling code
- ;
- com32_int_rm:
- pushf ; Flags on stack
- push cs ; Return segment
- push word .cont ; Return address
- push dword edx ; Segment:offset of IVT entry
- retf ; Invoke IVT routine
- .cont: ; ... on resume ...
- mov ebx,com32_int_resume
- jmp com32_enter_pm ; Go back to PM
-
- ;
- ; 16-bit system call handling code
- ;
- com32_sys_rm:
- pop gs
- pop fs
- pop es
- pop ds
- popad
- popfd
- mov [cs:Com32SysSP],sp
- retf ; Invoke routine
- .return:
- ; We clean up SP here because we don't know if the
- ; routine returned with RET, RETF or IRET
- mov sp,[cs:Com32SysSP]
- pushfd
- pushad
- push ds
- push es
- push fs
- push gs
- mov ebx,com32_sys_resume
- jmp com32_enter_pm
-
- ;
- ; 32-bit support code
- ;
- bits 32
-
- ;
- ; This is invoked on getting an interrupt in protected mode. At
- ; this point, we need to context-switch to real mode and invoke
- ; the interrupt routine.
- ;
- ; When this gets invoked, the registers are saved on the stack and
- ; AL contains the register number.
- ;
- com32_handle_interrupt:
- movzx eax,al
- xor ebx,ebx ; Actually makes the code smaller
- mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
- mov bx,com32_int_rm
- jmp com32_enter_rm ; Go to real mode
-
- com32_int_resume:
- popad
- iret
-
- ;
- ; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
- ; containing the com32sys_t structure from <com32.h> as well as
- ; the following entries (from low to high address):
- ; - Target offset
- ; - Target segment
- ; - Return offset
- ; - Return segment (== real mode cs == 0)
- ; - Return flags
- ;
- com32_farcall:
- pushfd ; Save IF among other things...
- pushad ; We only need to save some, but...
-
- mov eax,[esp+10*4] ; CS:IP
- jmp com32_syscall
-
-
- com32_intcall:
- pushfd ; Save IF among other things...
- pushad ; We only need to save some, but...
-
- movzx eax,byte [esp+10*4] ; INT number
- mov eax,[eax*4] ; Get CS:IP from low memory
-
- com32_syscall:
- cld
-
- movzx edi,word [word SavedSSSP]
- movzx ebx,word [word SavedSSSP+2]
- sub edi,54 ; Allocate 54 bytes
- mov [word SavedSSSP],di
- shl ebx,4
- add edi,ebx ; Create linear address
-
- mov esi,[esp+11*4] ; Source regs
- xor ecx,ecx
- mov cl,11 ; 44 bytes to copy
- rep movsd
-
- ; EAX is already set up to be CS:IP
- stosd ; Save in stack frame
- mov eax,com32_sys_rm.return ; Return seg:offs
- stosd ; Save in stack frame
- mov eax,[edi-12] ; Return flags
- and eax,0x200cd7 ; Mask (potentially) unsafe flags
- mov [edi-12],eax ; Primary flags entry
- stosw ; Return flags
-
- mov bx,com32_sys_rm
- jmp com32_enter_rm ; Go to real mode
-
- ; On return, the 44-byte return structure is on the
- ; real-mode stack, plus the 10 additional bytes used
- ; by the target address (see above.)
- com32_sys_resume:
- movzx esi,word [word SavedSSSP]
- movzx eax,word [word SavedSSSP+2]
- mov edi,[esp+12*4] ; Dest regs
- shl eax,4
- add esi,eax ; Create linear address
- and edi,edi ; NULL pointer?
- jnz .do_copy
- .no_copy: mov edi,esi ; Do a dummy copy-to-self
- .do_copy: xor ecx,ecx
- mov cl,11 ; 44 bytes
- rep movsd ; Copy register block
-
- add dword [word SavedSSSP],54 ; Remove from stack
-
- popad
- popfd
- ret ; Return to 32-bit program
-
- bits 16
-
- section .bss
- alignb 4
- PMESP resd 1 ; Protected-mode ESP
- Com32SysSP resw 1 ; SP saved during COM32 syscall
-
- section .text
-